使用 pip 安裝
# Win32
pip install pywin32
pip install ctypes comtypes
# 日期處理
pip install python-dateutil
# 計算文字寬度
pip install wcwidth
下載元大期貨行情 API 並安裝
http://easywin.yuantafutures.com.tw/api/download.html
New-PSDrive -PSProvider registry -Root HKEY_CLASSES_ROOT -Name HKCR | Out-Null; (Get-ItemProperty -Path "HKCR:\TypeLib\{350F911B-4F62-42AF-BCD5-83B431A4BBDF}\1.0" -Name "(default)")."(default)" -eq "YuantaQuote ActiveX Control module"
透過 ATL 串接封裝元大期貨行情 API 元件為 YuantaQuoteAXCtrl,並登入服務接收訊息。
import re
import ctypes
import comtypes
import comtypes.client
import datetime
import dateutil.relativedelta
import loguru
import wcwidth
import wx
class YuantaQuoteAXCtrl:
def __init__(self, parent):
# 父層元件必須是頂層視窗,才能正常接收事件
self.parent = parent
# 準備呼叫 ATL API 時所需參數
container = ctypes.POINTER(comtypes.IUnknown)()
control = ctypes.POINTER(comtypes.IUnknown)()
guid = comtypes.GUID()
sink = ctypes.POINTER(comtypes.IUnknown)()
# 建立 ActiveX 控制元件實體
ctypes.windll.atl.AtlAxCreateControlEx(
'YUANTAQUOTE.YuantaQuoteCtrl.1',
self.parent.Handle,
None,
ctypes.byref(container),
ctypes.byref(control),
ctypes.byref(guid),
sink
)
# 取得 ActiveX 控制元件實體
self.ctrl = comtypes.client.GetBestInterface(control)
# 綁定 ActiveX 控制元件事件
self.sink = comtypes.client.GetEvents(self.ctrl, self)
# 連線資訊
self.Host = None
self.Port = None
self.Username = None
self.Password = None
# 設定連線資訊
def Config(self, host, port, username, password):
self.Host = host
self.Port = port
self.Username = username
self.Password = password
# 登入元大服務
def Logon(self):
# 登入日盤主機
self.ctrl.SetMktLogon(
self.Username,
self.Password,
self.Host,
self.Port,
1,
0
)
# ActiveX 控制元件事件
def OnGetBreakResume(self,
symbol,
breakTime,
resumeTime,
reqType):
pass
# ActiveX 控制元件事件
def OnGetDelayClose(self,
symbol,
delayClose,
reqType):
pass
# ActiveX 控制元件事件
def OnGetDelayOpen(self,
symbol,
delayOpen,
reqType):
pass
# ActiveX 控制元件事件
def OnGetFutStatus(self,
symbol,
functionCode,
breakTime,
startTime,
reopenTime,
reqType):
pass
# ActiveX 控制元件事件
def OnGetLimitChange(self,
symbol,
functionCode,
statusTime,
level,
expandType,
reqType):
pass
# ActiveX 控制元件事件
def OnGetMktAll(self,
symbol,
refPri,
openPri,
highPri,
lowPri,
upPri,
dnPri,
matchTime,
matchPri,
matchQty,
tolMatchQty,
bestBuyQty,
bestBuyPri,
bestSellQty,
bestSellPri,
fdbPri,
fdbQty,
fdsPri,
fdsQty,
reqType):
pass
# ActiveX 控制元件事件
def OnGetMktData(self,
priType,
symbol,
qty,
pri,
reqType):
pass
# ActiveX 控制元件事件
def OnGetMktQuote(self,
symbol,
disClosure,
duration,
reqType):
pass
# ActiveX 控制元件事件
# 連線行為造成的狀態改變會從這個事件通知
def OnMktStatusChange(self,
status,
msg,
reqType):
# 取出訊息開頭可能存在的連線狀態代碼
code = ''
find = re.match(r'^(?P<code>\d).+$', msg)
if find:
code = msg[0]
msg = msg[1:]
# 去除訊息結尾可能存在的驚嘆號
if msg.endswith('!'):
msg = msg[:-1]
# 計算文字寬度並補上結尾空白
msg = msg + ' ' * (50 - wcwidth.wcswidth(msg))
# 產出欄位值
clX = f' {datetime.datetime.now():%H:%M:%S.%f} '
cl01 = f' {reqType: >7} '
cl02 = f' {status: >6} '
cl03 = f' {code: >4} '
cl04 = f' {msg} '
loguru.logger.info(
f'OnMktStatusChange\n' +
f'--------------------------------------------------------------------------------------------------\n' +
f'| | reqType | status | code | msg |\n' +
f'--------------------------------------------------------------------------------------------------\n' +
f'|{ clX}|{ cl01}|{ cl02}|{cl03}|{cl04 }|\n' +
f'--------------------------------------------------------------------------------------------------\n'
)
# ActiveX 控制元件事件
# 登入後不定期會接收到元大服務主機發送的時戳,供客戶端進行校時使用
def OnGetTimePack(self,
strTradeType,
strTime,
reqType):
clX = f' {datetime.datetime.now():%H:%M:%S.%f} '
cl01 = f' {reqType: >7} '
cl02 = f' {strTime[:2]}:{strTime[2:4]}:{strTime[4:6]}.{strTime[6:]} '
cl03 = f' {strTradeType: >12} '
loguru.logger.info(
f'OnGetTimePack\n' +
f'--------------------------------------------------------------\n' +
f'| | reqType | strTime | strTradeType |\n' +
f'--------------------------------------------------------------\n' +
f'|{ clX}|{ cl01}|{ cl02}|{ cl03}|\n' +
f'--------------------------------------------------------------\n'
)
# ActiveX 控制元件事件
def OnGetTradeStatus(self,
symbol,
tradeStatus,
reqType):
pass
# ActiveX 控制元件事件
def OnRegError(self,
symbol,
updMode,
errCode,
reqType):
pass
# ActiveX 控制元件事件
def OnTickRangeDataError(self,
symbol,
errCode,
reqType):
pass
# ActiveX 控制元件事件
def OnTickRegError(self,
symbol,
mode,
errCode,
reqType):
pass
def main():
app = wx.App()
frame = wx.Frame(
parent=None,
id=wx.ID_ANY,
title='Yuanta.Quote'
)
frame.Hide()
# 加入封裝後的元大期貨 API 報價元件
quote = YuantaQuoteAXCtrl(frame)
# 設定連線資訊
quote.Config(
host='<Host>',
port='<Port>',
username='<Username>',
password='<Password>'
)
# 登入元大服務
quote.Logon()
app.MainLoop()
if __name__ == '__main__':
loguru.logger.add(
f'{datetime.date.today():%Y%m%d}.log',
rotation='1 day',
retention='7 days',
level='DEBUG'
)
main()
團隊系列文:
CSScoke - 金魚都能懂的這個網頁畫面怎麼切 - 金魚都能懂了你還怕學不會嗎
Clarence - LINE bot 好好玩 30 天玩轉 LINE API
Hina Hina - 陣列大亂鬥
King Tzeng - IoT沒那麼難!新手用JavaScript入門做自己的玩具
Vita Ora - 好 Js 不學嗎 !? JavaScript 入門中的入門。
TaTaMo - 用Python開發的網頁不能放到Github上?Lektor說可以!!
不好意思,請教一下,我按照範例執行,一直出現
raise AttributeError(name)
AttributeError: SetMktLogon
有可能是什麼原因造成,感謝。
請問是否有按照流程註冊元大期貨 API 元件?
有,執行
New-PSDrive -PSProvider registry -Root HKEY_CLASSES_ROOT -Name HKCR | Out-Null; (Get-ItemProperty -Path "HKCR:\TypeLib\{350F911B-4F62-42AF-BCD5-83B431A4BBDF}\1.0" -Name "(default)")."(default)" -eq "YuantaQuote ActiveX Control module"
結果是True
Python 要裝 x86 版本喔
想請問一個問題:
系統windows 7 x86
python 3.8.5 x86
我在串接元大另外一套OneAPI的時候出現這個錯誤:
Traceback (most recent call last):
File "C:\Users\trevor\Desktop\HSUNJEN\YuantaOneOrder.py", line 9, in <module>
objYuantaOneAPI.Login(System.String('98875005091'), System.String('1234'))
System.NullReferenceException: 並未將物件參考設定為物件的執行個體。
於 YuantaOneAPI.YuantaOneAPITrader.Login(String Account, String Password)
原始碼:
import clr
import System
path = "c://Yuanta//ONE//YuantaOneAPI.dll"
clr.AddReference(path)
from YuantaOneAPI import YuantaOneAPITrader
objYuantaOneAPI = YuantaOneAPITrader()
objYuantaOneAPI.Open()
objYuantaOneAPI.Login(System.String('98875005091'), System.String('1234'))
因為在網路上找不到相關資料,又剛好看到版主這篇文章,所以就想請教一下版主要怎麼處理,感恩。
已解決,open後sleep1秒就可以登入了